#pragma once
#include <vector>
#include <queue>
#include <memory>
#include <functional>
#include <unistd.h>
#include<pthread.h>
#include "Task.hpp"
#include "Thread.hpp"
#include "BlockingQueue.hpp"

namespace wbj
{
#define THREAD_NUM 10

    template <class T>
    class ThreadPool
    {
        using func_t = std::function<void(T &)>;

    public:
        static ThreadPool<T>* getInstance(const func_t &func = [](T &task)
                                         { std::cout << task.getResult() << std::endl; })
        {
            if (_inst == nullptr)
            {
                LockGuard lock(&_mtx);
                if (_inst == nullptr)
                {
                    _inst = new ThreadPool<T>();

                    _inst->init();
                    _inst->start();
                }
            }

            _inst->_func = func;
            return _inst;
        }

    private:
        // 传递任务，线程数
        ThreadPool(int num = THREAD_NUM)
            : _num(num)
        {
        }

        ~ThreadPool()
        {
            for (auto &t : _threads)
                t.join();
        }

        ThreadPool(const ThreadPool<T> &) = delete;
    public:
        void init()
        {
            for(int i=0;i<_num;i++)
            {
                _threads.push_back(Thread(i,threadRoutine,this));
            }
        }

        void start()
        {
            for(auto& t:_threads)
            {
                t.run();
            }
        }

        static void threadRoutine(void* args)
        {
            pthread_detach(pthread_self());
            auto ptr=static_cast<ThreadPool<T>*>(args);

            while(true)
            {
                T task=ptr->popTask();

                task();
                ptr->callBack(task);
            }
        }

        void pushTask(const T& task)
        {
            _blockqueue.Push(task);
        }
    protected:
        func_t callBack(T& task)
        {
            _func(task);
        }
        T popTask()
        {
            T task;
            _blockqueue.Pop(&task);


            return task;
        }
    private:
        static ThreadPool<T> *_inst;
        static pthread_mutex_t _mtx;

        func_t _func;
        int _num;
        std::vector<Thread> _threads;
        BlockQueue<T> _blockqueue;
        
    };

    template <class T>
    ThreadPool<T> *ThreadPool<T>::_inst = nullptr;

    template <class T>
    pthread_mutex_t ThreadPool<T>::_mtx = PTHREAD_MUTEX_INITIALIZER;
}